home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 20
/
Cream of the Crop 20 (Terry Blount) (1996).iso
/
program
/
cppnl012.zip
/
cppnl012.txt
next >
Wrap
Text File
|
1996-06-28
|
12KB
|
413 lines
Issue #012
June, 1996
Contents:
New Language Feature - Mutable
Introduction to Templates Part 4 - Specializations
Using C++ as a Better C Part 12 - Function Parameter Names
Performance - Duplicate Inlines
NEW LANGUAGE FEATURE - MUTABLE
In C++ it's possible to have a class object instance that is constant
and cannot be modified by the program, once initially set up. For
example:
class A {
public:
int x;
A();
};
const A a;
void g()
{
a.x = 37;
}
is illegal. In a similar way, invoking a non-const member function on
a const object is also illegal:
class A {
public:
int x;
A();
void f();
};
const A a;
void g()
{
a.f();
}
The reason for this latter prohibition is due to separate
compilation. A::f() may be defined in some other translation unit,
and there's no way of knowing whether it modifies the object upon
which it operates.
It is possible to define const member functions:
void f() const;
that are allowed to operate on a const object instance. Such a
function does not modify the instance it operates on. The type of the
"this" pointer for a class T is normally:
T *const this;
meaning that the pointer cannot be changed. Within a const member
function, the type is:
const T *const this;
meaning that neither the pointer nor the pointed-at object instance
can be modified.
Recently a new feature has been added to C++ to selectively allow for
individual data class members to be modified even for a const object
instance, and lessen the need for casting away of const. For example:
class A {
public:
mutable int x;
A();
};
const A a;
void f()
{
a.x = 37;
}
This says that "x" can be modified even though it's a member of a
const object instance.
How useful "mutable" turns out to be remains to be seen. One cited
example for its use is within classes whose object instances appear
constant but actually do change their state internally. For example:
class Box {
double xll, yll; // lower left X,Y
double xur, yur; // upper right X,Y
double a; // cached area
public:
double area() const
{
a = (xur - xll) * (yur - yll);
return a;
}
class Box(double x1, double y1, double x2, double y2) :
xll(x1), yll(y1), xur(x2), yur(y2)
{
}
};
const Box b(1.0, 1.0, 11.0, 14.0);
void f()
{
b.area();
}
which is illegal usage unless we instead say:
class Box {
double xll, yll; // lower left X,Y
double xur, yur; // upper right X,Y
mutable double a; // cached area
public:
double area() const
{
a = (xur - xll) * (yur - yll);
return a;
}
class Box(double x1, double y1, double x2, double y2) :
xll(x1), yll(y1), xur(x2), yur(y2)
{
}
};
const Box b(1.0, 1.0, 11.0, 14.0);
void f()
{
b.area();
}
INTRODUCTION TO TEMPLATES PART 4 - SPECIALIZATIONS
In previous issues we've covered some of the basics of C++ templates.
Recall that a template is a class or function skeleton, and is
combined with specified type arguments to produce an actual class or
function.
Beyond this general mechanism, C++ also allows the programmer to
define specialized classes and functions that take the template and
implement it for particular types of template arguments.
Suppose, for example, that you have a String template, that supports
strings of most anything -- chars, ints, doubles, arbitrary class
types, and so on. Now, it's pretty likely that strings of characters
will be used heavily, so it might make sense to special case this
combination of template and template argument:
template <class T> class String {
// stuff
};
template <> class String<char> {
// stuff
};
String<char> x;
The "template <>" notation is fairly new and may not yet be
implemented in your local compiler.
This sequence is a bit different from:
template <class T> class String {
// stuff
};
String<char> x;
In this second case, the default implementation of String is used,
whereas in the specialization case, the programmer overrides the
default template and provides an implementation of String<char>.
For a function template, a specialization would be defined as:
template <class T> void f(T) {}
template <> void f(int) {}
It's also possible to have forward declarations of specializations:
template <class T> class String {};
template <> class String<double>;
or:
template <class T> void f(T) {}
template <> void f(unsigned short&);
A specialization must be declared or defined before use, so for
example:
template <class T> int f(T) {return 0;}
int i = f(12.34);
template <> int f(double) {return 37;}
is invalid.
An interesting quirk with function templates concerns the case where
you have a C function, mixed in with a function template and
specialization:
extern "C" void f(int);
template <class T> int f(T) {return 0;}
template <> int f(int)
{
f(37);
return 0;
}
The f(37) call here is not recursive. Both "void f(int)" and "int
f(int)" match the call, and the non-template is preferred in such a
case.
It's also possible to have nested specializations, as in:
template <class T> class A {
template <class U> class B {
template <class V> void f(V) {}
};
};
template <> template <> template <>
void A<float>::B<double>::f(long double) {}
and you can specialize special member types such as constructors:
struct A {
template <class T> A(T) {}
};
template <> A::A(short) {}
or static data members:
template <class T> struct A {
template <class U> struct B {
static int x;
};
};
template <> template <> int A<float>::B<long double>::x = 59;
Specializations are a way of special-casing templates for particular
argument types, and are useful in a variety of applications. But they
can also be abused and make code harder to understand, especially if a
reader of the code doesn't pick up on the fact that specializations
are present.
USING C++ AS A BETTER C PART 12 - FUNCTION PARAMETER NAMES
Suppose that you have a C++ function, and for some reason you don't
actually use all the function parameters:
int sum(int a, int b, int c)
{
return a + b; // c not used
}
Many compilers will give a warning in this case to the effect
"warning: parameter c not used". This is perfectly legal code but the
warning can be tedious to deal with.
C++ has a feature that allows you to simply omit the parameter name:
int sum(int a, int b, int)
{
return a + b;
}
and avoid the warning. This feature is especially handy when stubbing
out code. A similar feature exists in catch handlers used in
exception handling.
PERFORMANCE - DUPLICATE INLINES
Suppose that you have a bit of code such as:
inline long fact(long n)
{
if (n < 2)
return 1;
else
return n * fact(n - 1);
}
int main()
{
lon